package com.my.study.springframework.context.event;

import com.my.study.springframework.bean.factory.BeanFactory;
import com.my.study.springframework.context.ApplicationEvent;
import com.my.study.springframework.context.ApplicationListener;
import com.my.study.springframework.util.ErrorHandler;

import java.util.Collection;
import java.util.concurrent.Executor;

/**
 * @author: yidujun
 * @create: 2021/07/12 20:36
 */
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

    private Executor taskExecutor;

    private ErrorHandler errorHandler;

    /**
     * Create a new SimpleApplicationEventMulticaster.
     */
    public SimpleApplicationEventMulticaster() {
    }

    public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
        setBeanFactory(beanFactory);
    }

    @Override
    public void multicastEvent(final ApplicationEvent event) {
        Collection<ApplicationListener<?>> applicationListeners = getApplicationListeners(event);
        for (final ApplicationListener<?> applicationListener : applicationListeners) {
            Executor executor = getTaskExecutor();
            if (null != executor) {
                executor.execute(() -> invokeListener(applicationListener, event));
            }
            else {
                invokeListener(applicationListener, event);
            }

        }
    }

    protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
        ErrorHandler errorHandler = getErrorHandler();
        if (null != errorHandler) {
            try {
                doInvokeListener(listener, event);
            } catch (Throwable e) {
                errorHandler.handleError(e);
            }
        }
        else {
            doInvokeListener(listener, event);
        }
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        listener.onApplicationEvent(event);
    }

    protected Executor getTaskExecutor() {
        return taskExecutor;
    }

    public void setTaskExecutor(Executor taskExecutor) {
        this.taskExecutor = taskExecutor;
    }

    protected ErrorHandler getErrorHandler() {
        return errorHandler;
    }

    public void setErrorHandler(ErrorHandler errorHandler) {
        this.errorHandler = errorHandler;
    }
}
